/**
 * 
 * Copyright (C) 2011 Cody Stoutenburg . All rights reserved.
 *
 *       This program is free software; you can redistribute it and/or
 *       modify it under the terms of the GNU Lesser General Public License
 *       as published by the Free Software Foundation; either version 2.1
 *       of the License, or (at your option) any later version.
 *
 *       This program is distributed in the hope that it will be useful,
 *       but WITHOUT ANY WARRANTY; without even the implied warranty of
 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *       GNU Lesser General Public License for more details.
 *
 *       You should have received a copy of the GNU Lesser General Public License
 *       along with this program; if not, write to the Free Software
 *       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 * 
 */
package testAgent.behaviours;

import jade.core.behaviours.Behaviour;
import jade.core.behaviours.DataStore;
import jade.core.behaviours.FSMBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPANames;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.lang.acl.ACLMessage;

import java.io.IOException;

import tp3.gui.EquationProducer;
import udes.ds.agent.AbstractEquation;
import udes.ds.agent.Equation;

/**
 * @author Cody Stoutenburg
 * 
 */
public class WaitForSomeoneHaveSolvedBehaviours extends FSMBehaviour {
	private static final long serialVersionUID = -2023931201720952205L;

	private static final String SEND_REQUEST = "send request";
	private static final String REQUEST_SOLVE = "request solve";
	private static final String WAIT_FOR_RESULT = "wait result";
	private static final String RESULT_FOUND = "result found";

	private final String equationKey;
	private final String responseKey;
	private final String resultKey;
	private final DataStore sharedDatastore;
	private Behaviour previousRequest;
	private int currentSended;

	public WaitForSomeoneHaveSolvedBehaviours(DataStore ds, Equation equation,
			String result) {
		super();

		equationKey = "Equation";
		responseKey = "response";
		resultKey = result;
		currentSended = 0;

		sharedDatastore = new DataStore();
		sharedDatastore.put(equationKey, equation);
		// sharedDatastore.put(responseKey, )

		this.setDataStore(ds);

		registerDefaultTransition(SEND_REQUEST, REQUEST_SOLVE);

		registerTransition(REQUEST_SOLVE, WAIT_FOR_RESULT,
				RequestEquationSolveBehaviours.AGREE);
		registerTransition(REQUEST_SOLVE, SEND_REQUEST,
				RequestEquationSolveBehaviours.REFUSE);

		registerTransition(WAIT_FOR_RESULT, RESULT_FOUND,
				RequestEquationSolveBehaviours.RESULT_FOUND);
		registerTransition(WAIT_FOR_RESULT, SEND_REQUEST,
				RequestEquationSolveBehaviours.CORRUPT_RESPONSE);

		registerFirstState(new SendRequestBehaviour(), SEND_REQUEST);
		registerState(new RequestSolveBehaviour(), REQUEST_SOLVE);
		registerState(new EquationIsSolveBehaviours(), WAIT_FOR_RESULT);
		registerLastState(new EquationResult(), RESULT_FOUND);
	}

	private void sendRequest() {
		DFAgentDescription descriptor = new DFAgentDescription();
		descriptor.addOntologies(EquationProducer.EQUATION_ONTOLOGIE);

		try {
			DFAgentDescription[] all = DFService.search(this.myAgent,
					descriptor);

			if (currentSended >= all.length) {
				currentSended = 0;
			}

			if (all.length > 0) {
				ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
				msg.setProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST);

				// we get the user content and put it to the message
				msg.setContentObject((Equation) sharedDatastore
						.get(equationKey));

				msg.addReceiver(all[currentSended].getName());

				Behaviour request = new RequestEquationSolveBehaviours(
						this.myAgent, msg, sharedDatastore, responseKey,
						resultKey);
				myAgent.addBehaviour(request);

				if (previousRequest != null) {
					myAgent.removeBehaviour(previousRequest);
				}
				previousRequest = request;

				currentSended++;
			}
		} catch (FIPAException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private boolean isEquationSolve() {
		Equation request = (Equation) sharedDatastore.get(equationKey);
		Equation result = (Equation) sharedDatastore.get(resultKey);

		return AbstractEquation.verifyDerive(request, result);
	}

	private void finish() {
		getDataStore().put(resultKey, sharedDatastore.get(resultKey));
	}

	private class SendRequestBehaviour extends OneShotBehaviour {
		private static final long serialVersionUID = -7022668400489099684L;

		@Override
		public void action() {
			sendRequest();
		}
	}

	private class RequestSolveBehaviour extends Behaviour {
		private static final long serialVersionUID = -8016685326482682723L;

		private int returnVal;
		private boolean isFinish;

		public RequestSolveBehaviour() {
			super();
			isFinish = false;
			returnVal = RequestEquationSolveBehaviours.REFUSE;
		}

		@Override
		public void action() {
			int response = (Integer) sharedDatastore.get(responseKey);
			if (response != RequestEquationSolveBehaviours.NO_RESPONSE) {
				switch (response) {
				case RequestEquationSolveBehaviours.AGREE:
					returnVal = RequestEquationSolveBehaviours.AGREE;
					break;
				case RequestEquationSolveBehaviours.REFUSE:
					sharedDatastore.put(responseKey,
							RequestEquationSolveBehaviours.NO_RESPONSE);
					returnVal = RequestEquationSolveBehaviours.REFUSE;
					break;
				default:
					sharedDatastore.put(responseKey,
							RequestEquationSolveBehaviours.NO_RESPONSE);
					returnVal = RequestEquationSolveBehaviours.REFUSE;
					break;
				}
				isFinish = true;
			}
		}

		@Override
		public boolean done() {
			return isFinish;
		}

		@Override
		public int onEnd() {
			return returnVal;
		}
	}

	private class EquationResult extends OneShotBehaviour {
		private static final long serialVersionUID = -7457928988513333798L;

		@Override
		public void action() {
			finish();
		}
	}

	private class EquationIsSolveBehaviours extends Behaviour {
		private static final long serialVersionUID = 2454460650859326911L;

		private boolean isFirst = true;
		private int returnVal;
		private boolean isFinish;

		@Override
		public void action() {
			if (isFirst) {
				System.out.println("wait for result...");
				isFirst = false;
			}
			int response = (Integer) sharedDatastore.get(responseKey);
			switch (response) {
			case RequestEquationSolveBehaviours.RESULT_FOUND:
				if (isEquationSolve()) {
					returnVal = RequestEquationSolveBehaviours.RESULT_FOUND;
				} else {
					System.out.println("result is wrong");
					returnVal = RequestEquationSolveBehaviours.CORRUPT_RESPONSE;
				}
				sharedDatastore.put(responseKey,
						RequestEquationSolveBehaviours.NO_RESPONSE);
				isFinish = true;
				break;
			case RequestEquationSolveBehaviours.CORRUPT_RESPONSE:
				System.out.println("result is corrupt");
				returnVal = RequestEquationSolveBehaviours.CORRUPT_RESPONSE;
				isFinish = true;
				break;
			}
		}

		@Override
		public boolean done() {
			return isFinish;
		}

		@Override
		public int onEnd() {
			return returnVal;
		}
	}

}
